package main.model.hexisland;

import main.model.hexisland.location.HexLocation;
import main.model.hexisland.location.SubHexLocation;
import main.model.hexisland.location.SubHexLocationPath;

import java.util.ArrayList;
import java.util.Collection;

/**
 * Created with IntelliJ IDEA.
 * User: gabe
 * Date: 14/06/13
 * Time: 20:43
 * To change this template use File | Settings | File Templates.
 */
public class SubTileUtil extends TileUtil {

    /**
     * Flood-fill method for finding places that can be reached when unable to pass through obstacles.
     * @param range The number of steps which can be taken.
     * @param start The starting tile.
     * @return  An array of distances containing arrays of all the locations that can be accessed.
     */
    public static ArrayList<ArrayList<SubHexLocationPath>> findSubHexPathWithObstacles(
            HexIsland island, int range, SubHexLocation start, boolean allowsSmallCritters){

        Collection<SubHexLocation> visited = new ArrayList<SubHexLocation>();
        visited.add(start);
        ArrayList<ArrayList<SubHexLocationPath>> fringes = new ArrayList<ArrayList<SubHexLocationPath>>();
        fringes.add(new ArrayList<SubHexLocationPath>());
        fringes.get(0).add(new SubHexLocationPath(null,start));

        for(int k = 1; k < range; k++){
            fringes.add(k , new ArrayList<SubHexLocationPath>());
            for(SubHexLocationPath current: fringes.get(k-1)){
                if(island.getTileType(current) != null){
                    for(SubHexLocation neighbour : SubTileUtil.getNeighbours(
                            current, !island.hasCentralObstacle(current))){
                        if( ! visited.contains(neighbour)
                                && isAccessible(island , neighbour , ! allowsSmallCritters)){

                            visited.add(neighbour);
                            fringes.get(k).add(new SubHexLocationPath(current, neighbour));
                        }
                    }
                }
            }
        }
        return fringes;
    }

    public static boolean isAccessible(HexIsland island , SubHexLocation location , boolean allowSmallCritters){
        if(island.isAccessible(location)){
            if(!allowSmallCritters){
                if(island.hasCentralObstacle(location)){
                    HexLocation locationBorder = findNeighbour(location , location.getSector());
                    if(island.getTileType(locationBorder) != null
                            && (island.hasCentralObstacle(locationBorder)
                            || ! island.isAccessible(locationBorder))){
                        return false;
                    }
                }
                return true;
            }else return true;
        }else return false;
    }



    private static int transform(int bearing, int transform){
        bearing += transform;
        if (bearing > 5) bearing -= 6;
        if (bearing < 0) bearing += 6;
        return bearing;
    }

    /**
     * The locations accessible from the given subHex.
     * Legal movements are al the sub hex locations which are adjacent,
     * and all the locations which are accessible at the corner.
     * Has a boolean which if disabled, denys access across the centre of the tile.
     *
     * @param current  The subhex location to determine access from.
     * @param hasMiddleAccess   allows access across the centre of the tile
     * @return   a collection of locations which coul dbe accessible from the location.
     */
    public static Collection<SubHexLocation> getNeighbours(SubHexLocation current , boolean hasMiddleAccess){

        int s = current.getSector();
        Collection<SubHexLocation> allNeighbours = new ArrayList<SubHexLocation>();
        // Neighbours on current tile
        allNeighbours.add(new SubHexLocation(current, transform(s,+1))); // sector widdershins
        allNeighbours.add(new SubHexLocation(current, transform(s,-1))); // sector turnwise

        if(hasMiddleAccess){
            allNeighbours.add(new SubHexLocation(current, transform(s,+2)));
            allNeighbours.add(new SubHexLocation(current, transform(s,+3)));
            allNeighbours.add(new SubHexLocation(current, transform(s,+4)));
        }

        // Direct Adjacent neighbour
        HexLocation neighbour = TileUtil.findNeighbour(current, current.getSector());
        allNeighbours.add(new SubHexLocation(neighbour, transform(s,+2) )); // sector widdershins
        allNeighbours.add(new SubHexLocation(neighbour, transform(s,+3) )); // sector adjacent
        allNeighbours.add(new SubHexLocation(neighbour, transform(s,+4) )); // sector turnwise

        // Turnwise neighbour
        neighbour = TileUtil.findNeighbour(current, transform(s, -1));
        allNeighbours.add(new SubHexLocation(neighbour, transform(s,+1) ));
        allNeighbours.add(new SubHexLocation(neighbour, transform(s,+2) ));

        // Widdershins neighbour
        neighbour = TileUtil.findNeighbour(current, transform(s, +1));
        allNeighbours.add(new SubHexLocation(neighbour , transform(s,-1) ));
        allNeighbours.add(new SubHexLocation(neighbour , transform(s,-2) ));

        return allNeighbours;
    }
}